"""The functions to handle downloading and related functionality"""

from twisted.internet import reactor
from twisted.internet.protocol import ClientFactory
from twisted.protocols.basic import LineReceiver

import json

def addElements(tableWidget, elements, profileName, uniqueAtts):
    """Adds the requested elements to the tableWidget"""
    for element in elements:
        DownloadSong(element, tableWidget.addElements, profileName,
                     uniqueAtts, './downloads/')

class DownloadProtocol(LineReceiver):
    """The protocol associated with downloading a single song from the peer"""
    def connectionMade(self):
        self.outFile=None
        self.dataLeft=None
        self.transport.write(json.dumps([self.profileName,
                                         self.factory.reducedElement]))
    def lineReceived(self, line):
        ext, fileSize=json.loads(line)
        self.outFile=self.factory.getOutStream(ext)
        self.dataLeft=int(fileSize)
        self.setRawMode()
    def rawDataReceived(self, data):
        self.dataLeft-=len(data)
        self.outFile.write(data)
        if self.dataLeft<=0:
            self.transport.loseConnection()
            self.factory.finish()
    def __failure(self, connector, reason):
        self.factory.fail()
    clientConnectionFailed=clientConnectionLost=__failure
        
class DownloadSong(ClientFactory):
    """Downloads a song, and puts the updated element in the tableWidget"""
    protocol=DownloadProtocol
    def __init__(self, element, finishFn, uniqueAtts, profileName,
                 directory):
        self.reducedElement=dict((att, element[att]) for att in uniqueAtts)
        self.__uniqueAtts=uniqueAtts
        self.profileName=profileName
        self.__finishFn=finishFn
        self.__directory=directory
        peer=element['Location']
        reactor.connectTCP(peer['I.P.'], peer['Download Port'], self)
    def finish(self):
        """Finishes by calling the finish function of the element"""
        self.__finishFn([self.element])
    def getOutStream(self, extension):
        """Creates the output stream written to by the protocol"""
        topOnly=lambda val: val[0] if isinstance(val, list) else val
        filName='-'.join(topOnly(self.reducedElement[att])
                         for att in self.__uniqueAtts[::-1])
        fil='%s%s.%s'%(self.__directory, filName, extension)
        return open(fil, 'wb')
    def fail(self):
        print 'failed'

def downloadElements(elements, profileName, uniqueAtts, player):
    """Previews the elements by downloading them into a temporary folder, and
    running them through the player"""
    #This is a cool way to do this, but maybe not the clearest of ways, and
    #I do not know if it will work.
    gen=(DownloadSong(element, player.loadElements, profileName, uniqueAtts,
                     './temp') for element in elements)
    gen.next()
    player.sFinished.connect(gen.next)
